/*
* Copyright 2014 - 2017 Blazebit.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.blazebit.persistence.criteria.impl;
import com.blazebit.persistence.CriteriaBuilder;
import com.blazebit.persistence.FromBuilder;
import com.blazebit.persistence.FullQueryBuilder;
import com.blazebit.persistence.GroupByBuilder;
import com.blazebit.persistence.HavingBuilder;
import com.blazebit.persistence.JoinOnBuilder;
import com.blazebit.persistence.JoinType;
import com.blazebit.persistence.MultipleSubqueryInitiator;
import com.blazebit.persistence.OrderByBuilder;
import com.blazebit.persistence.SelectBuilder;
import com.blazebit.persistence.SelectObjectBuilder;
import com.blazebit.persistence.SubqueryBuilder;
import com.blazebit.persistence.SubqueryInitiator;
import com.blazebit.persistence.WhereBuilder;
import com.blazebit.persistence.criteria.BlazeAbstractQuery;
import com.blazebit.persistence.criteria.BlazeJoin;
import com.blazebit.persistence.criteria.BlazeOrder;
import com.blazebit.persistence.criteria.BlazeRoot;
import com.blazebit.persistence.criteria.BlazeSubquery;
import com.blazebit.persistence.criteria.impl.RenderContext.ClauseType;
import com.blazebit.persistence.criteria.impl.expression.AbstractSelection;
import com.blazebit.persistence.criteria.impl.expression.SubqueryExpression;
import com.blazebit.persistence.criteria.impl.path.AbstractFrom;
import com.blazebit.persistence.criteria.impl.path.AbstractJoin;
import com.blazebit.persistence.criteria.impl.path.RootImpl;
import com.blazebit.persistence.criteria.impl.path.TreatedPath;
import javax.persistence.Tuple;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;
import javax.persistence.criteria.Subquery;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author Christian Beikov
* @since 1.2.0
*/
public class InternalQuery<T> implements Serializable {
private static final long serialVersionUID = 1L;
private final BlazeAbstractQuery<T> owner;
private final BlazeCriteriaBuilderImpl criteriaBuilder;
private final boolean isSubQuery;
private boolean distinct;
private Selection<? extends T> selection;
private final Set<RootImpl<?>> roots = new LinkedHashSet<>();
private Set<AbstractFrom<?, ?>> correlationRoots;
private Predicate restriction;
private List<Expression<?>> groupList = Collections.emptyList();
private Predicate having;
private List<BlazeOrder> orderList = Collections.emptyList();
private List<Subquery<?>> subqueries;
public InternalQuery(BlazeAbstractQuery<T> owner, BlazeCriteriaBuilderImpl criteriaBuilder) {
this.owner = owner;
this.criteriaBuilder = criteriaBuilder;
this.isSubQuery = owner instanceof Subquery<?>;
}
/* Select */
public boolean isDistinct() {
return distinct;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
@SuppressWarnings("unchecked")
public Selection<T> getSelection() {
return (Selection<T>) selection;
}
public void setSelection(Selection<? extends T> selection) {
// NOTE: checks for duplicate aliases and predicate selects are already done
this.selection = selection;
}
/* From */
@SuppressWarnings("unchecked")
public Set<Root<?>> getRoots() {
return (Set<Root<?>>) (Set<?>) roots;
}
@SuppressWarnings("unchecked")
public Set<BlazeRoot<?>> getBlazeRoots() {
return (Set<BlazeRoot<?>>) (Set<?>) roots;
}
public <X> BlazeRoot<X> from(Class<X> entityClass, String alias) {
EntityType<X> entityType = criteriaBuilder.getEntityManagerFactory().getMetamodel().entity(entityClass);
if (entityType == null) {
throw new IllegalArgumentException(entityClass + " is not an entity");
}
return from(entityType, alias);
}
public <X> BlazeRoot<X> from(EntityType<X> entityType, String alias) {
RootImpl<X> root = new RootImpl<X>(criteriaBuilder, entityType, alias, true);
roots.add(root);
return root;
}
/* Correlation */
public void addCorrelationRoot(AbstractFrom<?, ?> fromImplementor) {
if (!isSubQuery) {
throw new IllegalStateException("Query is not identified as sub-query");
}
if (correlationRoots == null) {
correlationRoots = new HashSet<AbstractFrom<?, ?>>();
}
correlationRoots.add(fromImplementor);
}
public Set<Join<?, ?>> collectCorrelatedJoins() {
if (!isSubQuery) {
throw new IllegalStateException("Query is not identified as sub-query");
}
final Set<Join<?, ?>> correlatedJoins;
if (correlationRoots != null) {
correlatedJoins = new HashSet<Join<?, ?>>();
for (AbstractFrom<?, ?> correlationRoot : correlationRoots) {
correlatedJoins.addAll(correlationRoot.getJoins());
}
} else {
correlatedJoins = Collections.emptySet();
}
return correlatedJoins;
}
/* Where */
public Predicate getRestriction() {
return restriction;
}
public void setRestriction(Predicate restriction) {
this.restriction = restriction;
}
/* Group by */
public List<Expression<?>> getGroupList() {
return groupList;
}
public void setGroupList(List<Expression<?>> groupList) {
this.groupList = groupList;
}
/* Having */
public Predicate getGroupRestriction() {
return having;
}
public void setHaving(Predicate having) {
this.having = having;
}
/* Order by */
public List<BlazeOrder> getBlazeOrderList() {
return orderList;
}
public void setBlazeOrderList(List<BlazeOrder> orderList) {
this.orderList = orderList;
}
@SuppressWarnings({"unchecked"})
public List<Order> getOrderList() {
return (List<Order>) (List<?>) orderList;
}
@SuppressWarnings({"unchecked"})
public void setOrderList(List<Order> orderList) {
this.orderList = (List<BlazeOrder>) (List<?>) orderList;
}
/* Parameters */
public Set<ParameterExpression<?>> getParameters() {
// NOTE: we have to always visit them because it's not possible to cache that easily
ParameterVisitor visitor = new ParameterVisitor();
visitor.visit(selection);
visitor.visit(restriction);
if (subqueries != null) {
for (Subquery<?> subquery : subqueries) {
visitor.visit(subquery);
}
}
for (RootImpl<?> r : roots) {
r.visit(visitor);
}
for (AbstractFrom<?, ?> r : correlationRoots) {
r.visit(visitor);
}
visitor.visit(having);
if (groupList != null) {
for (Expression<?> grouping : groupList) {
visitor.visit(grouping);
}
}
if (orderList != null) {
for (Order ordering : orderList) {
visitor.visit(ordering.getExpression());
}
}
return visitor.getParameters();
}
/* Subquery */
public List<Subquery<?>> internalGetSubqueries() {
if (subqueries == null) {
subqueries = new ArrayList<Subquery<?>>();
}
return subqueries;
}
public <U> BlazeSubquery<U> subquery(Class<U> subqueryType) {
SubqueryExpression<U> subquery = new SubqueryExpression<U>(criteriaBuilder, subqueryType, owner);
internalGetSubqueries().add(subquery);
return subquery;
}
/* Rendering */
public CriteriaBuilder<T> render(CriteriaBuilder<T> cb) {
if (distinct) {
cb.distinct();
}
RenderContextImpl context = new RenderContextImpl();
renderFrom(cb, context);
List<TreatedPath<?>> treatedSelections = renderSelect(cb, context);
renderWhere(cb, context, treatedSelections);
renderGroupBy(cb, context);
renderHaving(cb, context);
renderOrderBy(cb, context);
for (ImplicitParameterBinding b : context.getImplicitParameterBindings()) {
b.bind(cb);
}
for (Map.Entry<String, ParameterExpression<?>> entry : context.getExplicitParameterNameMapping().entrySet()) {
cb.setParameterType(entry.getKey(), entry.getValue().getParameterType());
}
return cb;
}
public void renderSubquery(RenderContext context) {
RenderContextImpl contextImpl = (RenderContextImpl) context;
SubqueryInitiator<?> initiator = context.getSubqueryInitiator();
SubqueryBuilder<?> cb = renderSubqueryFrom(initiator, contextImpl);
if (distinct) {
cb.distinct();
}
List<TreatedPath<?>> treatedSelections = renderSelect(cb, contextImpl);
renderWhere(cb, contextImpl, treatedSelections);
renderGroupBy(cb, contextImpl);
renderHaving(cb, contextImpl);
renderOrderBy(cb, contextImpl);
cb.end();
}
private List<TreatedPath<?>> renderSelect(SelectBuilder<?> cb, final RenderContextImpl context) {
if (selection == null) {
return Collections.emptyList();
}
final List<TreatedPath<?>> treatedSelections = new ArrayList<>();
context.setClauseType(ClauseType.SELECT);
if (selection.isCompoundSelection()) {
Class<?> selectionType = selection.getJavaType();
if (selectionType.isArray()) {
for (Selection<?> s : selection.getCompoundSelectionItems()) {
renderSelection(cb, context, s, treatedSelections);
}
} else if (Tuple.class.isAssignableFrom(selectionType)) {
if (cb instanceof CriteriaBuilder) {
((CriteriaBuilder) cb).selectNew(new JpaTupleObjectBuilder(selection.getCompoundSelectionItems()) {
@Override
protected void renderSelection(SelectBuilder<?> cb, Selection<?> s) {
InternalQuery.this.renderSelection(cb, context, s, treatedSelections);
}
});
} else {
for (Selection<?> s : selection.getCompoundSelectionItems()) {
renderSelection(cb, context, s, treatedSelections);
}
}
} else {
if (!(cb instanceof FullQueryBuilder<?, ?>)) {
throw new IllegalArgumentException("Invalid subquery found that uses select new!");
}
SelectObjectBuilder<?> b = ((FullQueryBuilder<?, ?>) cb).selectNew(selectionType);
for (Selection<?> s : selection.getCompoundSelectionItems()) {
if (s instanceof Subquery<?>) {
if (s.getAlias() != null) {
context.pushSubqueryInitiator(b.withSubquery(s.getAlias()));
} else {
context.pushSubqueryInitiator(b.withSubquery());
}
((SubqueryExpression<?>) s).renderSubquery(context);
context.popSubqueryInitiator();
} else {
((AbstractSelection<?>) s).render(context);
String expr = context.takeBuffer();
Map<String, InternalQuery<?>> aliasToSubqueries = context.takeAliasToSubqueryMap();
if (aliasToSubqueries.isEmpty()) {
if (s.getAlias() != null && !(s instanceof AbstractFrom<?, ?>)) {
b.with(expr, s.getAlias());
} else {
b.with(expr);
}
} else {
MultipleSubqueryInitiator<?> initiator;
if (s.getAlias() != null) {
initiator = b.withSubqueries(expr, s.getAlias());
} else {
initiator = b.withSubqueries(expr);
}
for (Map.Entry<String, InternalQuery<?>> subqueryEntry : aliasToSubqueries.entrySet()) {
context.pushSubqueryInitiator(initiator.with(subqueryEntry.getKey()));
subqueryEntry.getValue().renderSubquery(context);
context.popSubqueryInitiator();
}
initiator.end();
}
}
}
b.end();
}
} else {
renderSelection(cb, context, selection, treatedSelections);
}
return treatedSelections;
}
private void renderSelection(SelectBuilder<?> cb, RenderContextImpl context, Selection<?> s, List<TreatedPath<?>> treatedSelections) {
if (s instanceof Subquery<?>) {
if (s.getAlias() != null) {
context.pushSubqueryInitiator(cb.selectSubquery(s.getAlias()));
} else {
context.pushSubqueryInitiator(cb.selectSubquery());
}
((SubqueryExpression<?>) s).renderSubquery(context);
context.popSubqueryInitiator();
} else {
if (s instanceof TreatedPath<?>) {
TreatedPath<?> treatedPath = (TreatedPath<?>) s;
treatedSelections.add(treatedPath);
treatedPath.getTreatedPath().render(context);
} else {
((AbstractSelection<?>) s).render(context);
}
String expr = context.takeBuffer();
Map<String, InternalQuery<?>> aliasToSubqueries = context.takeAliasToSubqueryMap();
if (aliasToSubqueries.isEmpty()) {
if (s.getAlias() != null && !(s instanceof AbstractFrom<?, ?>)) {
cb.select(expr, s.getAlias());
} else {
cb.select(expr);
}
} else {
MultipleSubqueryInitiator<?> initiator;
if (s.getAlias() != null) {
initiator = cb.selectSubqueries(expr, s.getAlias());
} else {
initiator = cb.selectSubqueries(expr);
}
for (Map.Entry<String, InternalQuery<?>> subqueryEntry : aliasToSubqueries.entrySet()) {
context.pushSubqueryInitiator(initiator.with(subqueryEntry.getKey()));
subqueryEntry.getValue().renderSubquery(context);
context.popSubqueryInitiator();
}
initiator.end();
}
}
}
private void renderFrom(FromBuilder<?> cb, RenderContextImpl context) {
context.setClauseType(ClauseType.FROM);
for (BlazeRoot<?> r : roots) {
((AbstractFrom<?, ?>) r).prepareAlias(context);
if (r.getAlias() != null) {
cb.from(r.getJavaType(), r.getAlias());
} else {
cb.from(r.getJavaType());
}
}
for (RootImpl<?> r : roots) {
renderJoins(cb, context, r, true);
}
}
@SuppressWarnings("unchecked")
private void renderJoins(FromBuilder<?> cb, RenderContextImpl context, AbstractFrom<?, ?> r, boolean fetching) {
String path;
if (r.getAlias() != null) {
path = r.getAlias();
} else {
path = "";
}
renderJoins(cb, true, context, path, (Set<BlazeJoin<?, ?>>) (Set<?>) r.getBlazeJoins());
Collection<TreatedPath<?>> treatedPaths = (Collection<TreatedPath<?>>) r.getTreatedPaths();
if (treatedPaths != null && treatedPaths.size() > 0) {
for (TreatedPath<?> treatedPath : treatedPaths) {
RootImpl<?> treatedRoot = (RootImpl<?>) treatedPath;
String treatedParentPath = "TREAT(" + path + " AS " + treatedPath.getTreatType().getName() + ')';
renderJoins(cb, fetching, context, treatedParentPath, (Set<BlazeJoin<?, ?>>) (Set<?>) treatedRoot.getBlazeJoins());
}
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private SubqueryBuilder<?> renderSubqueryFrom(SubqueryInitiator<?> initiator, RenderContextImpl context) {
SubqueryBuilder<?> cb = null;
context.setClauseType(ClauseType.FROM);
for (RootImpl<?> r : roots) {
r.prepareAlias(context);
if (cb == null) {
if (r.getAlias() != null) {
cb = initiator.from(r.getJavaType(), r.getAlias());
} else {
cb = initiator.from(r.getJavaType());
}
} else {
if (r.getAlias() != null) {
cb.from(r.getJavaType(), r.getAlias());
} else {
cb.from(r.getJavaType());
}
}
}
if (correlationRoots != null) {
for (AbstractFrom<?, ?> r : correlationRoots) {
r.prepareAlias(context);
Set<BlazeJoin<?, ?>> joins = (Set<BlazeJoin<?, ?>>) (Set<?>) r.getBlazeJoins();
for (BlazeJoin<?, ?> j : joins) {
AbstractJoin<?, ?> join = (AbstractJoin<?, ?>) j;
EntityType<?> treatJoinType = join.getTreatJoinType();
String path = getPath(r.getAlias(), j, treatJoinType);
if (cb == null) {
if (j.getAlias() != null) {
cb = initiator.from(path, j.getAlias());
} else {
cb = initiator.from(path);
}
} else {
if (j.getAlias() != null) {
cb.from(path, j.getAlias());
} else {
cb.from(path);
}
}
}
}
}
for (RootImpl<?> r : roots) {
renderJoins(cb, context, r, false);
}
if (correlationRoots != null) {
for (AbstractFrom<?, ?> r : correlationRoots) {
Set<BlazeJoin<?, ?>> joins = (Set<BlazeJoin<?, ?>>) (Set<?>) r.getBlazeJoins();
for (BlazeJoin<?, ?> j : joins) {
renderJoins(cb, context, (AbstractFrom<?, ?>) j, false);
}
}
}
return cb;
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void renderJoins(FromBuilder<?> cb, boolean fetching, RenderContextImpl context, String parentPath, Set<BlazeJoin<?, ?>> joins) {
if (joins.isEmpty()) {
return;
}
for (BlazeJoin<?, ?> j : joins) {
AbstractJoin<?, ?> join = (AbstractJoin<?, ?>) j;
EntityType<?> treatJoinType = join.getTreatJoinType();
join.prepareAlias(context);
// TODO: implicit joins?
String path = getPath(parentPath, j, treatJoinType);
String alias = j.getAlias();
JoinOnBuilder<?> onBuilder = null;
// "Join" relations in embeddables
if (j.getAttribute().getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED) {
alias = path;
} else {
if (j.getOn() != null) {
if (fetching && j.isFetch()) {
throw new IllegalArgumentException("Fetch joining with on-condition is not allowed!");
} else {
onBuilder = cb.joinOn(path, alias, getJoinType(j.getJoinType()));
}
} else {
if (fetching && j.isFetch()) {
((FullQueryBuilder<?, ?>) cb).join(path, alias, getJoinType(j.getJoinType()), true);
} else {
cb.join(path, alias, getJoinType(j.getJoinType()));
}
}
}
if (onBuilder != null) {
context.setClauseType(ClauseType.ON);
context.getBuffer().setLength(0);
((AbstractSelection<?>) j.getOn()).render(context);
String expression = context.takeBuffer();
Map<String, InternalQuery<?>> aliasToSubqueries = context.takeAliasToSubqueryMap();
if (aliasToSubqueries.isEmpty()) {
onBuilder.onExpression(expression);
} else {
MultipleSubqueryInitiator<?> initiator = onBuilder.onExpressionSubqueries(expression);
for (Map.Entry<String, InternalQuery<?>> subqueryEntry : aliasToSubqueries.entrySet()) {
context.pushSubqueryInitiator(initiator.with(subqueryEntry.getKey()));
subqueryEntry.getValue().renderSubquery(context);
context.popSubqueryInitiator();
}
initiator.end();
}
}
renderJoins(cb, fetching, context, alias, (Set<BlazeJoin<?, ?>>) (Set<?>) j.getBlazeJoins());
Collection<TreatedPath<?>> treatedPaths = (Collection<TreatedPath<?>>) join.getTreatedPaths();
if (treatedPaths != null && treatedPaths.size() > 0) {
for (TreatedPath<?> treatedPath : treatedPaths) {
AbstractJoin<?, ?> treatedJoin = (AbstractJoin<?, ?>) treatedPath;
String treatedParentPath = "TREAT(" + alias + " AS " + treatedPath.getTreatType().getName() + ')';
renderJoins(cb, fetching, context, treatedParentPath, (Set<BlazeJoin<?, ?>>) (Set<?>) treatedJoin.getBlazeJoins());
}
}
}
}
private String getPath(String parentPath, BlazeJoin<?, ?> j, EntityType<?> treatJoinType) {
String path = j.getAttribute().getName();
if (parentPath == null || parentPath.isEmpty()) {
if (treatJoinType != null) {
return "TREAT(" + path + " AS " + treatJoinType.getName() + ')';
} else {
return path;
}
}
if (treatJoinType != null) {
return "TREAT(" + parentPath + "." + path + " AS " + treatJoinType.getName() + ')';
} else {
return parentPath + "." + path;
}
}
private JoinType getJoinType(javax.persistence.criteria.JoinType joinType) {
switch (joinType) {
case INNER:
return JoinType.INNER;
case LEFT:
return JoinType.LEFT;
case RIGHT:
return JoinType.RIGHT;
default:
throw new IllegalArgumentException("Unsupported join type: " + joinType);
}
}
private void renderWhere(WhereBuilder<?> wb, RenderContextImpl context, List<TreatedPath<?>> treatedSelections) {
if (restriction == null) {
if (!treatedSelections.isEmpty()) {
renderTreatTypeRestrictions(context, treatedSelections);
String expression = context.takeBuffer();
wb.whereExpression(expression);
}
return;
}
context.setClauseType(ClauseType.WHERE);
context.getBuffer().setLength(0);
((AbstractSelection<?>) restriction).render(context);
renderTreatTypeRestrictions(context, treatedSelections);
String expression = context.takeBuffer();
Map<String, InternalQuery<?>> aliasToSubqueries = context.takeAliasToSubqueryMap();
if (aliasToSubqueries.isEmpty()) {
wb.whereExpression(expression);
} else {
MultipleSubqueryInitiator<?> initiator = wb.whereExpressionSubqueries(expression);
for (Map.Entry<String, InternalQuery<?>> subqueryEntry : aliasToSubqueries.entrySet()) {
context.pushSubqueryInitiator(initiator.with(subqueryEntry.getKey()));
subqueryEntry.getValue().renderSubquery(context);
context.popSubqueryInitiator();
}
initiator.end();
}
}
private void renderTreatTypeRestrictions(RenderContextImpl context, List<TreatedPath<?>> treatedSelections) {
final StringBuilder buffer = context.getBuffer();
boolean first = buffer.length() == 0;
for (TreatedPath<?> p : treatedSelections) {
if (first) {
first = false;
} else {
buffer.append(" AND ");
}
buffer.append("TYPE(")
.append(p.getAlias())
.append(") = ")
.append(p.getTreatType().getName());
}
}
private void renderGroupBy(GroupByBuilder<?> gb, RenderContextImpl context) {
if (groupList == null) {
return;
}
context.setClauseType(ClauseType.GROUP_BY);
for (Expression<?> expr : groupList) {
context.getBuffer().setLength(0);
((AbstractSelection<?>) expr).render(context);
String expression = context.takeBuffer();
Map<String, InternalQuery<?>> aliasToSubqueries = context.takeAliasToSubqueryMap();
if (aliasToSubqueries.isEmpty()) {
gb.groupBy(expression);
} else {
throw new IllegalArgumentException("Subqueries are not supported in the group by clause!");
// MultipleSubqueryInitiator<?> initiator = gb.groupBySubqueries(expression);
//
// for (Map.Entry<String, InternalQuery<?>> subqueryEntry : aliasToSubqueries.entrySet()) {
// context.pushSubqueryInitiator(initiator.with(subqueryEntry.getKey()));
// subqueryEntry.getValue().renderSubquery(context);
// context.popSubqueryInitiator();
// }
//
// initiator.end();
}
}
}
private void renderHaving(HavingBuilder<?> hb, RenderContextImpl context) {
if (having == null) {
return;
}
context.setClauseType(ClauseType.HAVING);
context.getBuffer().setLength(0);
((AbstractSelection<?>) having).render(context);
String expression = context.takeBuffer();
Map<String, InternalQuery<?>> aliasToSubqueries = context.takeAliasToSubqueryMap();
if (aliasToSubqueries.isEmpty()) {
hb.havingExpression(expression);
} else {
MultipleSubqueryInitiator<?> initiator = hb.havingExpressionSubqueries(expression);
for (Map.Entry<String, InternalQuery<?>> subqueryEntry : aliasToSubqueries.entrySet()) {
context.pushSubqueryInitiator(initiator.with(subqueryEntry.getKey()));
subqueryEntry.getValue().renderSubquery(context);
context.popSubqueryInitiator();
}
initiator.end();
}
}
private void renderOrderBy(OrderByBuilder<?> ob, RenderContextImpl context) {
if (orderList == null) {
return;
}
context.setClauseType(ClauseType.ORDER_BY);
for (Order order : orderList) {
context.getBuffer().setLength(0);
((AbstractSelection<?>) order.getExpression()).render(context);
String expression = context.takeBuffer();
Map<String, InternalQuery<?>> aliasToSubqueries = context.takeAliasToSubqueryMap();
if (aliasToSubqueries.isEmpty()) {
boolean nullsFirst = false;
if (order instanceof BlazeOrder) {
nullsFirst = ((BlazeOrder) order).isNullsFirst();
}
ob.orderBy(expression, order.isAscending(), nullsFirst);
} else {
throw new IllegalArgumentException("Subqueries are not supported in the order by clause!");
// MultipleSubqueryInitiator<?> initiator = ob.groupBySubqueries(expression);
//
// for (Map.Entry<String, InternalQuery<?>> subqueryEntry : aliasToSubqueries.entrySet()) {
// context.pushSubqueryInitiator(initiator.with(subqueryEntry.getKey()));
// subqueryEntry.getValue().renderSubquery(context);
// context.popSubqueryInitiator();
// }
//
// initiator.end();
}
}
}
}